
package YPTServerRegister

import (
	"time"
	"os"
	"google.golang.org/grpc"
	pb "git.oschina.net/YPTArch/ypt_service_discovery/etcd"
	"encoding/json"
	"context"
	"fmt"
	"os/signal"
	"syscall"
)

type Register struct {
	EtcdEndPoints []string
	HeartBeatTick time.Duration   //心跳
	RegisterKey string  //向ETCD注册键
	kvClient pb.KVClient
	con *grpc.ClientConn
	heartBeatTick int
	Code string
	rInfo RegisterInfo
}
						//api名    方法    isAuth
type ApiInfo map[string] []string   // "apiName" : ["post",1]

type Address struct{
	Host string
	Port int
}
type containerCode []string   //标识每个docker容器的ID，当此数组为空时，才删除Host

type RegisterInfo struct {
	Host string
	Port int
	Api ApiInfo
}

type EtcdSavedData struct{
	Addr []Address
	Api ApiInfo
	ContainerCode containerCode
}

func NewRegisterClient(etcdEndPoints []string,registerKey string, info RegisterInfo) (r *Register, err error){
	//注册信息
	r = &Register{
		EtcdEndPoints : etcdEndPoints,
		RegisterKey : registerKey,// + "/" + getRandomMD5String(),
		heartBeatTick : 10,
		rInfo : info,
		Code : getRandomMD5String(),
	}
	if err := r.registerService();err != nil{
		return nil,err
	}

	listenSIG(r)//监听信号量来判断服务是否关闭，关闭的话则主动从etcd中删除
	w := NewRegWatchCli(r)//添加watch
	watch(r.RegisterKey,r.kvClient,w.processDelete,w.processNew)
	return r,err
}


func (r *Register) registerService() error{
	con,err := grpc.Dial(simpleEtcdBalancer(r.EtcdEndPoints),grpc.WithInsecure())
	r.con = con
	if err != nil{
		return err
	}
	r.kvClient = pb.NewKVClient(con)
	if err = r.register();err != nil{
		return err
	}
	return nil
}
func (r *Register) register()error{
	//首先从ETCD上检查是否有重复
	sData ,repeat ,err := r.checkRepeat()
	etcdResMap[r.RegisterKey] = &sData //初始化赋值
	if err != nil {
		return nil
	}
	//没重复
	if !repeat{
		if StructEmpty(sData,EtcdSavedData{}) { //数据为空
			sData = EtcdSavedData{
				Addr : []Address{{r.rInfo.Host,r.rInfo.Port}},
				Api : r.rInfo.Api,
				ContainerCode : containerCode{r.Code},//分配一个code
			}
		}else{//有数据，添加新的节点
			sData.Addr = append(sData.Addr,Address{r.rInfo.Host,r.rInfo.Port})
			sData.ContainerCode = append(sData.ContainerCode,r.Code)
		}
	}else{
		sData.ContainerCode = append(sData.ContainerCode,r.Code)
	}


	jsonD , err := json.Marshal(sData)
	if err != nil{
		return err
	}
	res,err := r.kvClient.Put(context.Background(),&pb.PutRequest{
		Key : []byte(r.RegisterKey),
		Value : jsonD,
	//	Lease : id,
	})
	if err != nil{
		return err
	}
	fmt.Println("service " + r.RegisterKey + " registered success!\n",res.Header)
	return nil

}

//检查etcd返回的数据里面的地址是否有重复的
func (r *Register) checkRepeat() (EtcdSavedData ,bool, error){
	results, err := r.kvClient.Range(context.Background(),&pb.RangeRequest{
		Key : []byte(r.RegisterKey),
	})
	if err != nil{
		fmt.Println("err",err)
		return EtcdSavedData{},false ,err
	}
	if results.Kvs == nil {//数据为空,返回空
		return EtcdSavedData{},false , nil
	}
	var data EtcdSavedData
	json.Unmarshal(results.Kvs[0].Value,&data)
	for _,v := range data.Addr{
		if v.Host == r.rInfo.Host && v.Port == r.rInfo.Port{//有相同的
			return data,true ,nil
		}
	}
	return data, false , nil
}

func (r *Register) unRegisterService() error{
	results, err := r.kvClient.Range(context.Background(),&pb.RangeRequest{
		Key : []byte(r.RegisterKey),
	})
	if err != nil{
		fmt.Println("check key error  ",err)
		os.Exit(1)
	}
	if results.Kvs == nil {
		os.Exit(1)
	}
	var data EtcdSavedData
	json.Unmarshal(results.Kvs[0].Value,&data)



	//最后一个服务死掉
	if len(data.ContainerCode) == 1 && data.ContainerCode[0] == r.Code{
		res, err := r.kvClient.DeleteRange(context.Background(),&pb.DeleteRangeRequest{
			Key : []byte(r.RegisterKey),
			//PrevKv : true,
		})
		if err != nil{
			fmt.Println("remove service error ",err)
			return err
		}
		r.kvClient.DeleteRange(context.Background(),&pb.DeleteRangeRequest{
			Key : []byte(r.RegisterKey + "/code/"+r.Code),
		})
		fmt.Println("delete from etcd success! ",res)
	}else{
		codesList := make([]string,0)
		for _,v := range data.ContainerCode{
			if v!= r.Code{
				codesList = append(codesList,v)
			}
		}

		canDeleteHost := true //是否删除host

		for _,v := range codesMap[r.RegisterKey]{
			if v.Host == r.rInfo.Host && v.Port == r.rInfo.Port && v.Code != r.Code{
				canDeleteHost = false
				break
			}
		}
		addrs := make([]Address,0)
		if canDeleteHost{
			for _,v := range data.Addr{
				if v.Host == r.rInfo.Host && v.Port == r.rInfo.Port{
					continue
				}
				addrs = append(addrs,v)
			}
			//etcdResMap[key].Addr = addrs
			data.Addr = addrs
		}
		data.ContainerCode = codesList

		jsonD,err := json.Marshal(data)
		if err != nil{
			os.Exit(1)
		}
		r.kvClient.Put(context.Background(),&pb.PutRequest{//
			Key : []byte(r.RegisterKey),
			Value : jsonD,
		})
		r.kvClient.DeleteRange(context.Background(),&pb.DeleteRangeRequest{
			Key : []byte(r.RegisterKey + "/code/"+r.Code),
		})
	}

	return nil
}

//定期清理键的历史记录，不然会无期限的增长
func (r *Register) compactHistory(rev int64){
	r.kvClient.Compact(context.Background(),&pb.CompactionRequest{
		Revision : rev,
		Physical : true,
	})
}

func listenSIG(r *Register){
	sigs := make(chan os.Signal,1)
	signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM,syscall.SIGKILL,syscall.SIGQUIT)   //http://blog.csdn.net/yikai2009/article/details/8643818

	go func(){
		sig := <- sigs
		fmt.Println("signals -> ",sig)
		r.unRegisterService()
		os.Exit(1)
	}()

}
